#include "bsp_can.h"
#include "stm32f10x_can.h"
#include "drivers.h"

FlexcanData mCanData;
CanRxMsg g_can_rx[RX_BUFFER_SIZE];

void bsp_can_init(uint8_t velocity)
{
    CAN_InitTypeDef CAN_InitStructure;
    uint8_t i;

    bsp_can_enable(TRUE);
    bsp_can_nvic_init();
    bsp_can_gpio_init();

    CAN_DeInit(CAN1);
    CAN_StructInit(&CAN_InitStructure);

    CAN_InitStructure.CAN_TTCM = DISABLE;
    CAN_InitStructure.CAN_ABOM = DISABLE;
    CAN_InitStructure.CAN_AWUM = DISABLE;
    CAN_InitStructure.CAN_NART = DISABLE;
    CAN_InitStructure.CAN_RFLM = DISABLE;
    CAN_InitStructure.CAN_TXFP = DISABLE;
    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
    CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
    CAN_InitStructure.CAN_BS1 = CAN_BS1_11tq;
    CAN_InitStructure.CAN_BS2 = CAN_BS2_6tq;
    CAN_InitStructure.CAN_Prescaler = velocity;
    CAN_Init(CAN1, &CAN_InitStructure);

    mCanData.rx_size = RX_BUFFER_SIZE;
    mCanData.p_rx_msg = g_can_rx;
    mCanData.w_offset = 0;
    mCanData.r_offset = 0;
    mCanData.rx_count = 0;
    for(i = 0; i < FILTER_SIZE; i++) {
        mCanData.filter_id[i] = 0x0000;
    }
}

void bsp_can_enable(uint8_t enable)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    if(enable == TRUE) {
        GPIO_ResetBits(GPIOA, GPIO_Pin_8);
        GPIO_ResetBits(GPIOC, GPIO_Pin_9);
    } else {
        GPIO_SetBits(GPIOA, GPIO_Pin_8);
        GPIO_SetBits(GPIOC, GPIO_Pin_9);
    }
}

void bsp_can_nvic_init(void)
{
    NVIC_InitTypeDef  NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void bsp_can_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APBxPeriph_CAN_IO |
            RCC_APB2Periph_AFIO,
            ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,
            ENABLE);
    GPIO_InitStructure.GPIO_Pin = CAN_RXD;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(CAN_IO, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = CAN_TXD;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(CAN_IO, &GPIO_InitStructure);

    if(CAN_PinRemap == ENABLE) {
        GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    }
}

void bsp_can_filter(uint32_t id1, uint32_t id2, uint32_t mid1, uint32_t mid2)
{
    CAN_FilterInitTypeDef  CAN_FilterInitStructure;

    CAN_FilterInitStructure.CAN_FilterNumber=1;
    CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
    CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;
    CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5;
    CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mid1<<5;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow=mid2<<5;
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;
    CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
    CAN_FilterInit(&CAN_FilterInitStructure);
    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
}

void bsp_can_send(CanTxMsg *txMsg)
{
    u32 count = 0;
    u8 transmitMailBox;
#if CAN_DEBUG
    uint8_t i;

    printf("send -> %04x ", txMsg->StdId);
    for(i = 0; i < 8; i++) {
        printf("%02x ", txMsg->Data[i]);
    }
    printf("\r\n");
#endif
    txMsg->IDE = CAN_ID_STD;
    transmitMailBox = CAN_Transmit(CAN1, txMsg);
    while(CAN_TransmitStatus(CAN1, transmitMailBox) != CANTXOK) {
        count ++;
        if(count > 1000000) {
            loge("%s: timeout", __func__);
            break;
        }
    }
}

uint8_t bsp_can_recv(CanRxMsg *rxMsg)
{
    uint16_t count;

#if uCOS_EN == 1 
    CPU_SR_ALLOC();
#endif

    DISABLE_INT();
    count = mCanData.rx_count;
    ENABLE_INT();

    if (count == 0)	/* 已经没有数据 */
    {
        return FALSE;
    }
    else
    {
        memcpy(rxMsg, &mCanData.p_rx_msg[mCanData.r_offset], sizeof(CanRxMsg));
        /* 改写FIFO读索引 */
        DISABLE_INT();
        if (++mCanData.r_offset >= mCanData.rx_size)
        {
            mCanData.r_offset = 0;
        }
        mCanData.rx_count --;
        ENABLE_INT();
        return TRUE;
    }
}

void bsp_can_clear(void)
{
#if uCOS_EN == 1 
    CPU_SR_ALLOC();
#endif

    DISABLE_INT();
    mCanData.w_offset = 0;
    mCanData.r_offset = 0;
    mCanData.rx_count = 0;
    ENABLE_INT();
}

void flexcan_rx_callack(void)
{
    CanRxMsg rxMsg;
    uint8_t i;

#if uCOS_EN == 1 
    CPU_SR_ALLOC();

    CPU_CRITICAL_ENTER();
    OSIntEnter();                                          
    CPU_CRITICAL_EXIT();
#endif

    CAN_Receive(CAN1, CAN_FIFO0, &rxMsg);
#if CAN_DEBUG
    printf("recv <- %04x ", rxMsg.StdId);
    for(i = 0; i < 8; i++) {
        printf("%02x ", rxMsg.Data[i]);
    }
    printf("\r\n");
#endif
    memcpy(&mCanData.p_rx_msg[mCanData.w_offset], &rxMsg, sizeof(CanRxMsg));
    if(++mCanData.w_offset >= mCanData.rx_size) {
        mCanData.w_offset = 0;
    }

    if(mCanData.rx_count < mCanData.rx_size) {
        mCanData.rx_count ++;
    }

#if uCOS_EN == 1 
    OSIntExit(); 
#endif
}
